# !/usr/bin/env python
# -*- coding:utf-8 -*-
"""
功能：1.1 节
版本：2022-04-02 22:00 创建
"""
import collections
import math
import unittest


class Section001TestCase(unittest.TestCase):
    def test_001(self):
        Card = collections.namedtuple('Card', ['rank', 'suit'])

        class FrenchDeck:
            ranks = [str(i) for i in range(2, 11)] + list('JQKA')
            suits = ('spades', 'diamonds', 'clubs', 'hearts')

            def __init__(self):
                self._cards = [Card(rank, suit) for suit in self.suits
                               for rank in self.ranks]

            def __len__(self) -> int:
                return len(self._cards)

            def __getitem__(self, position: int) -> Card:
                return self._cards[position]

        deck = FrenchDeck()

        # 获取长度
        self.assertEqual(13 * 4, len(deck))

        # 获取元素，切片
        self.assertEqual('2', deck[0].rank)
        self.assertEqual('spades', deck[0].suit)

        #  隐式迭代，没有实现 __contains__ 方法，in 运算符就会按顺序做一次迭代搜索。
        self.assertTrue(Card('9', 'clubs') in deck)

        # 可迭代，实现了 __getitem__ 方法
        for elem in deck:
            print(elem)

    def test_002(self):
        def check_same_dimension(call):
            def fun_core(one, other):
                """校验维度是否相同

                :param one: Vector,一个向量
                :param other: Vector,另外一个向量
                :return:
                """
                if len(one.data) != len(other):
                    raise ValueError(f'数组维数不同:Vector<{len(one.data)}>+Vector<{len(other)}>')
                return call(one, other)

            return fun_core

        class Vector:
            def __init__(self, *args):
                self.data = args

            def __len__(self):
                return len(self.data)

            def __getitem__(self, idx):
                return self.data[idx]

            def __eq__(self, other):
                for i in range(len(self.data)):
                    if self.data[i] != other[i]:
                        return False
                return True

            def __repr__(self):
                return f'Vector({",".join([str(i) for i in self.data])})'

            def check_same_dimension_class(call):
                def fun_core(cls, other):
                    """校验维度是否相同

                    :param other: Vector,另外一个向量
                    :return:
                    """
                    if len(cls.data) != len(other):
                        raise ValueError(f'数组维数不同:Vector<{len(cls.data)}>+Vector<{len(other)}>')
                    return call(cls, other)

                return fun_core

            @check_same_dimension
            def __add__(self, other):
                # 重载"+"运算符
                result = []
                for i in range(len(self.data)):
                    result.append(self.data[i] + other[i])
                return Vector(*result)

            def __radd__(self, other):
                # 加法满足交换律
                return self + other

            @check_same_dimension_class
            def __sub__(self, other):
                # 重载"-"运算符
                result = []
                for i in range(len(self.data)):
                    result.append(self.data[i] - other[i])
                return Vector(*result)

            @check_same_dimension
            def __mul__(self, other) -> float:
                # 重载"*"运算符,
                result = 0
                for i in range(len(self.data)):
                    result += self.data[i] * other[i]
                return result

            def __abs__(self):
                # 计算几何距离:sqrt(x1**2 + x2**2 + ...)
                return math.hypot(*self.data)

        v1 = Vector(1, 1)
        v2 = Vector(2, 3)
        v3 = v1 + v2
        self.assertEqual('Vector(3,4)', str(v3))
        self.assertEqual(5, abs(v3))
        self.assertEqual(Vector(3, 4), v3)
        self.assertEqual(Vector(1, 2), v2 - v1)
        self.assertEqual(5, v1 * v2)
        v1 + Vector(1, 2, 3)


if __name__ == '__main__':
    unittest.main()
